﻿namespace QuickMail.BusinessLogic
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    using HigLabo.Net.Imap;
    using HigLabo.Net.Smtp;
    using HigLabo.Net.Pop3;
    using QuickMail.DataModels;
    using QuickMail.Properties;
    
    using MailMessage = HigLabo.Mime.MailMessage;
    using SmtpClient = HigLabo.Net.Smtp.SmtpClient;   

    public class MailsWorker
    {
        #region Fields

        private long _totalMailsCount = -1;
        private readonly List<ImapFolder> _tempImapFolders = new List<ImapFolder>();

        #endregion //Fields

        #region Send

        /// <summary>
        /// The method of sending the letter.
        /// </summary>
        public bool SendMessage(SmtpMessage message)
        {
            try
            {
                using (var smtpClient = new SmtpClient(Settings.Default.SendServer)
                {
                    AuthenticateMode = HelpWorker.GetAuthenticateMode(),
                    EncryptedCommunication = HelpWorker.GetCryptType(),
                    Port = Settings.Default.SendPort,
                    UserName = Settings.Default.SendEmail,
                    Password = CryptWorker.Decrypt(Settings.Default.SendPassword)
                })
                {
                    if (!smtpClient.Authenticate())
                        return false;

                    var result = smtpClient.SendMail(message);
                    if (result.SendSuccessful == false)
                    {
                        StaticFields.Logger.Error(" -- {0}.{1} -- {2}", GetType().FullName,
                            System.Reflection.MethodBase.GetCurrentMethod().Name,
                            "Invalid send mail. State: " + result.State);

                        return false;
                    }

                    return true;
                }
            }
            catch (Exception ex)
            {
                StaticFields.Logger.Error(" -- {0}.{1} -- {2}", GetType().FullName,
                    System.Reflection.MethodBase.GetCurrentMethod().Name, ex.Message);
                return false;
            }
        }

        #endregion //Send

        #region Receive

        /// <summary>
        /// Checks for new messages by the POP3 protocol.
        /// </summary>
        public IEnumerable<MailMessage> Pop3CheckNewMails()
        {
            using (var pop3Client = new Pop3Client(Settings.Default.GetServer)
            {
                Port = Settings.Default.GetPort,
                UserName = Settings.Default.GetEmail,
                Password = CryptWorker.Decrypt(Settings.Default.GetPassword),
                Ssl = Settings.Default.GetUseSsl
            })
            {
                var mailMessages = new List<MailMessage>();
                if (pop3Client.Authenticate())
                {
                    var currentMailsCount = pop3Client.GetTotalMessageCount();

                    if (_totalMailsCount < 0 || _totalMailsCount >= currentMailsCount)
                    {
                        _totalMailsCount = currentMailsCount;
                        pop3Client.Close();
                        return mailMessages;
                    }

                    for (long i = _totalMailsCount + 1; i <= currentMailsCount; i++)
                    {
                        mailMessages.Add(pop3Client.GetMessage(i));
                    }

                    _totalMailsCount = currentMailsCount;
                    pop3Client.Close();
                }
                return mailMessages;
            }
        }

        /// <summary>
        /// Checks for new messages by the IMAP protocol.
        /// </summary>
        public IEnumerable<MailMessage> ImapCheckNewMails()
        {
            var mailMessages = new List<MailMessage>();
            try
            {
                using (var imapClient = new ImapClient(Settings.Default.GetServer)
                {
                    Port = Settings.Default.GetPort,
                    UserName = Settings.Default.GetEmail,
                    Password = CryptWorker.Decrypt(Settings.Default.GetPassword),
                    Ssl = Settings.Default.GetUseSsl
                })
                {
                    if (imapClient.Authenticate())
                    {
                        List<ImapFolder> allFolders = imapClient.GetAllFolders();
                        ImapFolder selectFolder;

                        if (!_tempImapFolders.Any())
                        {
                            foreach (var imapFolder in allFolders)
                            {
                                //todo does not correctly work with gmail
                                selectFolder = imapClient.SelectFolder(imapFolder.Name);
                                _tempImapFolders.Add(imapFolder);
                                _tempImapFolders[_tempImapFolders.Count - 1].MailCount = selectFolder.MailCount;

                                //try
                                //{
                                //    selectFolder = imapClient.SelectFolder(imapFolder.Name);
                                //    _tempImapFolders.Add(imapFolder);
                                //    _tempImapFolders[_tempImapFolders.Count - 1].MailCount = selectFolder.MailCount;
                                //}
                                //catch (Exception ex)
                                //{
                                //    MainWindow.Logger.Error(" -- MailWorker.ImapCheckNewMails -- "
                                //                            + "Failed to select a folder." + ex.Message);
                                //}
                            }

                            return mailMessages;
                        }

                        for (int i = 0; i < allFolders.Count; i++)
                        {
                            if (i >= _tempImapFolders.Count)
                                break;

                            selectFolder = imapClient.SelectFolder(allFolders[i].Name);
                            if (selectFolder.MailCount > _tempImapFolders[i].MailCount)
                            {
                                for (int j = _tempImapFolders[i].MailCount + 1; j <= selectFolder.MailCount; j++)
                                {
                                    mailMessages.Add(imapClient.GetMessage(j));
                                }

                                _tempImapFolders[i].MailCount = selectFolder.MailCount;
                            }
                            else
                            {
                                _tempImapFolders[i].MailCount = selectFolder.MailCount;
                            }
                        }
                    }
                    return mailMessages;
                }
            }
            catch (Exception ex)
            {
                StaticFields.Logger.Error(" -- {0}.{1} -- {2}", GetType().FullName,
                    System.Reflection.MethodBase.GetCurrentMethod().Name, ex.Message);
                return mailMessages;
            }
        }

        #endregion //Receive
    }
}
